const utilsModule = ((Function) => {
  // context == ctx
  Function.prototype.MyApply = function (ctx, args) {
    ctx = ctx ? Object(ctx) : window;
    ctx.originFn = this;

    if(typeof args !== 'object' && typeof args !== 'function'){
      throw new TypeError('CreateList ....')
    }
    if(!args || typeOf(args) !== 'Array'){
      return ctx.originFn()
    }

    var res = eval('ctx.originFn(' + args + ')');
    delete ctx.originFn;
    return res
  }
  
  function typeOf(value) {
    if (value === null) {
      return 'null'
    }

    // var types = {
    //   '[object Object]': 'Object',
    //   '[object Array]': 'Array',
    //   '[object Number]': 'Number',
    //   '[object String]': 'String',
    //   '[object Boolean]': 'Boolean'
    // };
    // if(typeof(value) === 'object'){
    //   var res = ({}).toString.call(value);
    //   var type = types[res];
    // }

    return typeof (value) === 'object' ? {
      '[object Object]': 'Object',
      '[object Array]': 'Array',
      '[object Number]': 'Number',
      '[object String]': 'String',
      '[object Boolean]': 'Boolean',
    }[({}).toString.call(value)] : typeof(value)
  }

})(Function)


// call test
// function test(){
//   console.log(this,arguments);

//   return 'Over'
// }

// function test1(){}

// var res = test.MyCall(
//   // a:2,
//   // b:2
//   true
// ,'zhangshan','lisi')  // { a: 1, b: 2 }
// console.log(res);


// apply test
function test() {
  console.log(this, arguments);
}

test.MyApply({
  a: 1,
  b: 2
}, [2, 3, 4])

